/*
 * ip_address.cpp
 *
 *  Created on: 2008-11-25
 *      Author: fanliangliang
 */

#include "ip_address.h"
#include <string>
#include <cstring>

BEGIN_NAMESPACE_TOXIC

using namespace std;

IpAddress IpAddress::ANY("0.0.0.0");
IpAddress IpAddress::BROADCAST("255.255.255.255");
IpAddress IpAddress::LOCALHOST("127.0.0.1");

IpAddress::IpAddress(uint32_t address /*= INADDR_ANY*/) {
	setAddress(address);
}

IpAddress::IpAddress(const char* address) {
	setAddress(address);
}

IpAddress::IpAddress(const string& address) {
	setAddress(address.c_str());
}

IpAddress::~IpAddress() {

}

void IpAddress::setAddress(uint32_t address) {
	_value = address;
	_isValueKnown = true;
	_isStrKnown = false;
}

void IpAddress::setAddress(const char* address) {
	_str = address;
	_isValueKnown = false;
	_isStrKnown = true;
}

void IpAddress::setAddress(const string& address) {
	setAddress(address.c_str());
}

uint32_t IpAddress::value() const {
	if (!_isValueKnown) {
		_value = inet_addr(_str.c_str());
		_isValueKnown = true;
	}
	return _value;
}

const string& IpAddress::toString() const {
	if (!_isStrKnown) {
		in_addr a;
		a.s_addr = _value;
		_str = inet_ntoa(a);
		_isStrKnown = true;
	}
	return _str;
}

bool IpAddress::isValid() const {
	if (_isValueKnown && !_isStrKnown) {
		return true;
	}
	return value() != INADDR_NONE || toString() == "255.255.255.255";
}

IpAddress IpAddress::resolve(const string& hostname) {
	hostent* ph = gethostbyname(hostname.c_str());
	if (ph != 0) {
		in_addr a;
		memcpy(&a.s_addr, ph->h_addr_list[0], ph->h_length);
		return IpAddress(a.s_addr);
	}
	return IpAddress::ANY;
}


#if defined(PLATFORM_WIN32)

IpAddress IpAddress::local() {
	char hostname[256] = { 0 };
	if (gethostname(hostname, sizeof(hostname)) == 0) {
		return IpAddress::resolve(hostname);
	}
	return IpAddress::ANY;
}

#else

IpAddress IpAddress::local() {

	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sock != -1) {
		struct ifreq ifr;
		struct sockaddr_in sin;

		strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
		ifr.ifr_name[IFNAMSIZ - 1] = '\0';

		if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) {
			memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
			return IpAddress(sin.sin_addr.s_addr);
		}
	}
	return IpAddress::ANY;
}

#endif


bool operator==(const IpAddress& lhs, const IpAddress& rhs) {
	return lhs.value() == rhs.value() && lhs.toString() == rhs.toString();
}

bool operator!=(const IpAddress& lhs, const IpAddress& rhs) {
	return !(lhs == rhs);
}

ostream& operator<<(ostream& out, const IpAddress& address) {
	return out << address.toString();
}

END_NAMESPACE_TOXIC
